package xredis

import (
	"context"
	"github.com/redis/go-redis/v9"
	"github.com/spf13/cast"
	"time"
)

func (c *Client) Del(ctx context.Context, keys ...string) *redis.IntCmd {
	return c.Client.Del(ctx, c.formatKeys(keys...)...)
}

func (c *Client) Unlink(ctx context.Context, keys ...string) *redis.IntCmd {
	return c.Client.Unlink(ctx, c.formatKeys(keys...)...)
}

func (c *Client) Dump(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.Dump(ctx, c.formatKeys(key)[0])
}

func (c *Client) Exists(ctx context.Context, keys ...string) *redis.IntCmd {
	return c.Client.Exists(ctx, c.formatKeys(keys...)...)
}

func (c *Client) Expire(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd {
	return c.Client.Expire(ctx, c.formatKeys(key)[0], expiration)
}
func (c *Client) ExpireAt(ctx context.Context, key string, tm time.Time) *redis.BoolCmd {
	return c.Client.ExpireAt(ctx, c.formatKeys(key)[0], tm)
}
func (c *Client) ExpireNX(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd {
	return c.Client.ExpireNX(ctx, c.formatKeys(key)[0], expiration)
}
func (c *Client) ExpireXX(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd {
	return c.Client.ExpireXX(ctx, c.formatKeys(key)[0], expiration)
}
func (c *Client) ExpireGT(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd {
	return c.Client.ExpireGT(ctx, c.formatKeys(key)[0], expiration)
}
func (c *Client) ExpireLT(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd {
	return c.Client.ExpireLT(ctx, c.formatKeys(key)[0], expiration)
}

func (c *Client) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *redis.StatusCmd {
	return c.Client.Migrate(ctx, host, port, c.formatKeys(key)[0], db, timeout)
}
func (c *Client) Move(ctx context.Context, key string, db int) *redis.BoolCmd {
	return c.Client.Move(ctx, c.formatKeys(key)[0], db)
}
func (c *Client) ObjectRefCount(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.ObjectRefCount(ctx, c.formatKeys(key)[0])
}
func (c *Client) ObjectEncoding(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.ObjectEncoding(ctx, c.formatKeys(key)[0])
}
func (c *Client) ObjectIdleTime(ctx context.Context, key string) *redis.DurationCmd {
	return c.Client.ObjectIdleTime(ctx, c.formatKeys(key)[0])
}
func (c *Client) Persist(ctx context.Context, key string) *redis.BoolCmd {
	return c.Client.Persist(ctx, c.formatKeys(key)[0])
}
func (c *Client) PExpire(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd {
	return c.Client.PExpire(ctx, c.formatKeys(key)[0], expiration)
}
func (c *Client) PExpireAt(ctx context.Context, key string, tm time.Time) *redis.BoolCmd {
	return c.Client.PExpireAt(ctx, c.formatKeys(key)[0], tm)
}
func (c *Client) PTTL(ctx context.Context, key string) *redis.DurationCmd {
	return c.Client.PTTL(ctx, c.formatKeys(key)[0])
}

func (c *Client) Rename(ctx context.Context, key, newkey string) *redis.StatusCmd {
	return c.Client.Rename(ctx, c.formatKeys(key)[0], c.formatKeys(newkey)[0])
}
func (c *Client) RenameNX(ctx context.Context, key, newkey string) *redis.BoolCmd {
	return c.Client.RenameNX(ctx, c.formatKeys(key)[0], c.formatKeys(newkey)[0])
}
func (c *Client) Restore(ctx context.Context, key string, ttl time.Duration, value string) *redis.StatusCmd {
	return c.Client.Restore(ctx, c.formatKeys(key)[0], ttl, value)
}
func (c *Client) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *redis.StatusCmd {
	return c.Client.RestoreReplace(ctx, c.formatKeys(key)[0], ttl, value)
}
func (c *Client) Sort(ctx context.Context, key string, sort *redis.Sort) *redis.StringSliceCmd {
	return c.Client.Sort(ctx, c.formatKeys(key)[0], sort)
}
func (c *Client) SortRO(ctx context.Context, key string, sort *redis.Sort) *redis.StringSliceCmd {
	return c.Client.SortRO(ctx, c.formatKeys(key)[0], sort)
}
func (c *Client) SortStore(ctx context.Context, key, store string, sort *redis.Sort) *redis.IntCmd {
	return c.Client.SortStore(ctx, c.formatKeys(key)[0], store, sort)
}
func (c *Client) SortInterfaces(ctx context.Context, key string, sort *redis.Sort) *redis.SliceCmd {
	return c.Client.SortInterfaces(ctx, c.formatKeys(key)[0], sort)
}
func (c *Client) Touch(ctx context.Context, keys ...string) *redis.IntCmd {
	return c.Client.Touch(ctx, c.formatKeys(keys...)...)
}
func (c *Client) TTL(ctx context.Context, key string) *redis.DurationCmd {
	return c.Client.TTL(ctx, c.formatKeys(key)[0])
}
func (c *Client) Type(ctx context.Context, key string) *redis.StatusCmd {
	return c.Client.Type(ctx, c.formatKeys(key)[0])
}

func (c *Client) Append(ctx context.Context, key, value string) *redis.IntCmd {
	return c.Client.Append(ctx, c.formatKeys(key)[0], value)
}
func (c *Client) Decr(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.Decr(ctx, c.formatKeys(key)[0])
}
func (c *Client) DecrBy(ctx context.Context, key string, decrement int64) *redis.IntCmd {
	return c.Client.DecrBy(ctx, c.formatKeys(key)[0], decrement)
}
func (c *Client) Get(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.Get(ctx, c.formatKeys(key)[0])
}
func (c *Client) GetRange(ctx context.Context, key string, start, end int64) *redis.StringCmd {
	return c.Client.GetRange(ctx, c.formatKeys(key)[0], start, end)
}
func (c *Client) GetSet(ctx context.Context, key string, value interface{}) *redis.StringCmd {
	return c.Client.GetSet(ctx, c.formatKeys(key)[0], value)
}
func (c *Client) GetEx(ctx context.Context, key string, expiration time.Duration) *redis.StringCmd {
	return c.Client.GetEx(ctx, c.formatKeys(key)[0], expiration)
}
func (c *Client) GetDel(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.GetDel(ctx, c.formatKeys(key)[0])
}
func (c *Client) Incr(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.Incr(ctx, c.formatKeys(key)[0])
}
func (c *Client) IncrBy(ctx context.Context, key string, value int64) *redis.IntCmd {
	return c.Client.IncrBy(ctx, c.formatKeys(key)[0], value)
}
func (c *Client) IncrByFloat(ctx context.Context, key string, value float64) *redis.FloatCmd {
	return c.Client.IncrByFloat(ctx, c.formatKeys(key)[0], value)
}

func (c *Client) MGet(ctx context.Context, keys ...string) *redis.SliceCmd {
	return c.Client.MGet(ctx, c.formatKeys(keys...)...)
}

// MSet 多个key value 操作
// 不支持Struct
func (c *Client) MSet(ctx context.Context, values ...interface{}) *redis.StatusCmd {
	a := c.formatMSetValues(values...)
	if len(a) == 0 {
		return c.Client.MSet(ctx, values...)
	}
	newVal := make([]interface{}, 0)
	for k, v := range a {
		newVal = append(newVal, c.formatKeys(k)[0], v)
	}
	return c.Client.MSet(ctx, newVal...)
}

// MSetNX 多个key value 操作
// 不支持Struct
func (c *Client) MSetNX(ctx context.Context, values ...interface{}) *redis.BoolCmd {
	a := c.formatMSetValues(values...)
	if len(a) == 0 {
		return c.Client.MSetNX(ctx, values...)
	}
	newVal := make([]interface{}, 0)
	for k, v := range a {
		newVal = append(newVal, c.formatKeys(k)[0], v)
	}
	return c.Client.MSetNX(ctx, newVal...)
}
func (c *Client) formatMSetValues(values ...interface{}) map[string]interface{} {
	a := make(map[string]interface{})
	if len(values) == 1 {
		switch v := values[0].(type) {
		case map[string]interface{}:
			a = v
		case []string:
			l := len(v)
			for i, u := range v {
				if i%2 == 0 {
					if (i + 1) < l {
						a[u] = v[i+1]
					} else {
						a[u] = ""
					}
				}
			}
		}
	} else {
		l := len(values)
		for i, u := range values {
			v := cast.ToString(u)
			if i%2 == 0 {
				if (i + 1) < l {
					a[v] = values[i+1]
				} else {
					a[v] = ""
				}
			}
		}
	}

	return a
}

func (c *Client) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.StatusCmd {
	return c.Client.Set(ctx, c.formatKeys(key)[0], value, expiration)
}
func (c *Client) SetArgs(ctx context.Context, key string, value interface{}, a redis.SetArgs) *redis.StatusCmd {
	return c.Client.SetArgs(ctx, c.formatKeys(key)[0], value, a)
}
func (c *Client) SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.StatusCmd {
	return c.Client.SetEx(ctx, c.formatKeys(key)[0], value, expiration)

}
func (c *Client) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.BoolCmd {
	return c.Client.SetNX(ctx, c.formatKeys(key)[0], value, expiration)

}
func (c *Client) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.BoolCmd {
	return c.Client.SetXX(ctx, c.formatKeys(key)[0], value, expiration)
}
func (c *Client) SetRange(ctx context.Context, key string, offset int64, value string) *redis.IntCmd {
	return c.Client.SetRange(ctx, c.formatKeys(key)[0], offset, value)

}
func (c *Client) StrLen(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.StrLen(ctx, c.formatKeys(key)[0])
}
func (c *Client) Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *redis.IntCmd {
	return c.Client.Copy(ctx, c.formatKeys(sourceKey)[0], c.formatKeys(destKey)[0], db, replace)

}

func (c *Client) GetBit(ctx context.Context, key string, offset int64) *redis.IntCmd {
	return c.Client.GetBit(ctx, c.formatKeys(key)[0], offset)
}
func (c *Client) SetBit(ctx context.Context, key string, offset int64, value int) *redis.IntCmd {
	return c.Client.SetBit(ctx, c.formatKeys(key)[0], offset, value)
}
func (c *Client) BitCount(ctx context.Context, key string, bitCount *redis.BitCount) *redis.IntCmd {
	return c.Client.BitCount(ctx, c.formatKeys(key)[0], bitCount)
}
func (c *Client) BitOpAnd(ctx context.Context, destKey string, keys ...string) *redis.IntCmd {
	return c.Client.BitOpAnd(ctx, c.formatKeys(destKey)[0], c.formatKeys(keys...)...)
}
func (c *Client) BitOpOr(ctx context.Context, destKey string, keys ...string) *redis.IntCmd {
	return c.Client.BitOpOr(ctx, c.formatKeys(destKey)[0], c.formatKeys(keys...)...)
}
func (c *Client) BitOpXor(ctx context.Context, destKey string, keys ...string) *redis.IntCmd {
	return c.Client.BitOpXor(ctx, c.formatKeys(destKey)[0], c.formatKeys(keys...)...)
}
func (c *Client) BitOpNot(ctx context.Context, destKey string, key string) *redis.IntCmd {
	return c.Client.BitOpNot(ctx, c.formatKeys(destKey)[0], c.formatKeys(key)[0])
}
func (c *Client) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *redis.IntCmd {
	return c.Client.BitPos(ctx, c.formatKeys(key)[0], bit, pos...)
}
func (c *Client) BitField(ctx context.Context, key string, args ...interface{}) *redis.IntSliceCmd {
	return c.Client.BitField(ctx, c.formatKeys(key)[0], args...)
}

func (c *Client) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *redis.ScanCmd {
	return c.Client.SScan(ctx, c.formatKeys(key)[0], cursor, match, count)
}
func (c *Client) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *redis.ScanCmd {
	return c.Client.HScan(ctx, c.formatKeys(key)[0], cursor, match, count)
}
func (c *Client) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *redis.ScanCmd {
	return c.Client.ZScan(ctx, c.formatKeys(key)[0], cursor, match, count)
}

func (c *Client) HDel(ctx context.Context, key string, fields ...string) *redis.IntCmd {
	return c.Client.HDel(ctx, c.formatKeys(key)[0], fields...)
}
func (c *Client) HExists(ctx context.Context, key, field string) *redis.BoolCmd {
	return c.Client.HExists(ctx, c.formatKeys(key)[0], field)
}
func (c *Client) HGet(ctx context.Context, key, field string) *redis.StringCmd {
	return c.Client.HGet(ctx, c.formatKeys(key)[0], field)
}
func (c *Client) HGetAll(ctx context.Context, key string) *redis.MapStringStringCmd {
	return c.Client.HGetAll(ctx, c.formatKeys(key)[0])
}
func (c *Client) HIncrBy(ctx context.Context, key, field string, incr int64) *redis.IntCmd {
	return c.Client.HIncrBy(ctx, c.formatKeys(key)[0], field, incr)
}
func (c *Client) HIncrByFloat(ctx context.Context, key, field string, incr float64) *redis.FloatCmd {
	return c.Client.HIncrByFloat(ctx, c.formatKeys(key)[0], field, incr)
}
func (c *Client) HKeys(ctx context.Context, key string) *redis.StringSliceCmd {
	return c.Client.HKeys(ctx, c.formatKeys(key)[0])
}
func (c *Client) HLen(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.HLen(ctx, c.formatKeys(key)[0])
}
func (c *Client) HMGet(ctx context.Context, key string, fields ...string) *redis.SliceCmd {
	return c.Client.HMGet(ctx, c.formatKeys(key)[0], fields...)
}
func (c *Client) HSet(ctx context.Context, key string, values ...interface{}) *redis.IntCmd {
	return c.Client.HSet(ctx, c.formatKeys(key)[0], values...)
}
func (c *Client) HMSet(ctx context.Context, key string, values ...interface{}) *redis.BoolCmd {
	return c.Client.HMSet(ctx, c.formatKeys(key)[0], values...)
}
func (c *Client) HSetNX(ctx context.Context, key, field string, value interface{}) *redis.BoolCmd {
	return c.Client.HSetNX(ctx, c.formatKeys(key)[0], field, value)
}
func (c *Client) HVals(ctx context.Context, key string) *redis.StringSliceCmd {
	return c.Client.HVals(ctx, c.formatKeys(key)[0])
}
func (c *Client) HRandField(ctx context.Context, key string, count int) *redis.StringSliceCmd {
	return c.Client.HRandField(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) HRandFieldWithValues(ctx context.Context, key string, count int) *redis.KeyValueSliceCmd {
	return c.Client.HRandFieldWithValues(ctx, c.formatKeys(key)[0], count)
}

func (c *Client) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *redis.StringSliceCmd {
	return c.Client.BLPop(ctx, timeout, c.formatKeys(keys...)...)
}
func (c *Client) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *redis.StringSliceCmd {
	return c.Client.BRPop(ctx, timeout, c.formatKeys(keys...)...)
}
func (c *Client) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *redis.StringCmd {
	return c.Client.BRPopLPush(ctx, c.formatKeys(source)[0], c.formatKeys(destination)[0], timeout)
}
func (c *Client) LIndex(ctx context.Context, key string, index int64) *redis.StringCmd {
	return c.Client.LIndex(ctx, c.formatKeys(key)[0], index)
}
func (c *Client) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *redis.IntCmd {
	return c.Client.LInsert(ctx, c.formatKeys(key)[0], op, pivot, value)
}
func (c *Client) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *redis.IntCmd {
	return c.Client.LInsertBefore(ctx, c.formatKeys(key)[0], pivot, value)
}
func (c *Client) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *redis.IntCmd {
	return c.Client.LInsertAfter(ctx, c.formatKeys(key)[0], pivot, value)
}
func (c *Client) LLen(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.LLen(ctx, c.formatKeys(key)[0])
}
func (c *Client) LPop(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.LPop(ctx, c.formatKeys(key)[0])
}
func (c *Client) LPopCount(ctx context.Context, key string, count int) *redis.StringSliceCmd {
	return c.Client.LPopCount(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) LPos(ctx context.Context, key string, value string, args redis.LPosArgs) *redis.IntCmd {
	return c.Client.LPos(ctx, c.formatKeys(key)[0], value, args)
}
func (c *Client) LPosCount(ctx context.Context, key string, value string, count int64, args redis.LPosArgs) *redis.IntSliceCmd {
	return c.Client.LPosCount(ctx, c.formatKeys(key)[0], value, count, args)
}
func (c *Client) LPush(ctx context.Context, key string, values ...interface{}) *redis.IntCmd {
	return c.Client.LPush(ctx, c.formatKeys(key)[0], values...)
}
func (c *Client) LPushX(ctx context.Context, key string, values ...interface{}) *redis.IntCmd {
	return c.Client.LPushX(ctx, c.formatKeys(key)[0], values...)
}
func (c *Client) LRange(ctx context.Context, key string, start, stop int64) *redis.StringSliceCmd {
	return c.Client.LRange(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) LRem(ctx context.Context, key string, count int64, value interface{}) *redis.IntCmd {
	return c.Client.LRem(ctx, c.formatKeys(key)[0], count, value)
}
func (c *Client) LSet(ctx context.Context, key string, index int64, value interface{}) *redis.StatusCmd {
	return c.Client.LSet(ctx, c.formatKeys(key)[0], index, value)
}
func (c *Client) LTrim(ctx context.Context, key string, start, stop int64) *redis.StatusCmd {
	return c.Client.LTrim(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) RPop(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.RPop(ctx, c.formatKeys(key)[0])
}
func (c *Client) RPopCount(ctx context.Context, key string, count int) *redis.StringSliceCmd {
	return c.Client.RPopCount(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) RPopLPush(ctx context.Context, source, destination string) *redis.StringCmd {
	return c.Client.RPopLPush(ctx, c.formatKeys(source)[0], c.formatKeys(destination)[0])
}
func (c *Client) RPush(ctx context.Context, key string, values ...interface{}) *redis.IntCmd {
	return c.Client.RPush(ctx, c.formatKeys(key)[0], values...)
}
func (c *Client) RPushX(ctx context.Context, key string, values ...interface{}) *redis.IntCmd {
	return c.Client.RPushX(ctx, c.formatKeys(key)[0], values...)
}
func (c *Client) LMove(ctx context.Context, source, destination, srcpos, destpos string) *redis.StringCmd {
	return c.Client.LMove(ctx, c.formatKeys(source)[0], c.formatKeys(destination)[0], srcpos, destpos)
}
func (c *Client) BLMove(ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration) *redis.StringCmd {
	return c.Client.BLMove(ctx, c.formatKeys(source)[0], c.formatKeys(destination)[0], srcpos, destpos, timeout)
}

func (c *Client) SAdd(ctx context.Context, key string, members ...interface{}) *redis.IntCmd {
	return c.Client.SAdd(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) SCard(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.SCard(ctx, c.formatKeys(key)[0])
}
func (c *Client) SDiff(ctx context.Context, keys ...string) *redis.StringSliceCmd {
	return c.Client.SDiff(ctx, c.formatKeys(keys...)...)
}
func (c *Client) SDiffStore(ctx context.Context, destination string, keys ...string) *redis.IntCmd {
	return c.Client.SDiffStore(ctx, c.formatKeys(destination)[0], c.formatKeys(keys...)...)
}
func (c *Client) SInter(ctx context.Context, keys ...string) *redis.StringSliceCmd {
	return c.Client.SInter(ctx, c.formatKeys(keys...)...)
}
func (c *Client) SInterCard(ctx context.Context, limit int64, keys ...string) *redis.IntCmd {
	return c.Client.SInterCard(ctx, limit, c.formatKeys(keys...)...)
}
func (c *Client) SInterStore(ctx context.Context, destination string, keys ...string) *redis.IntCmd {
	return c.Client.SInterStore(ctx, c.formatKeys(destination)[0], c.formatKeys(keys...)...)
}
func (c *Client) SIsMember(ctx context.Context, key string, member interface{}) *redis.BoolCmd {
	return c.Client.SIsMember(ctx, c.formatKeys(key)[0], member)
}
func (c *Client) SMIsMember(ctx context.Context, key string, members ...interface{}) *redis.BoolSliceCmd {
	return c.Client.SMIsMember(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) SMembers(ctx context.Context, key string) *redis.StringSliceCmd {
	return c.Client.SMembers(ctx, c.formatKeys(key)[0])
}
func (c *Client) SMembersMap(ctx context.Context, key string) *redis.StringStructMapCmd {
	return c.Client.SMembersMap(ctx, c.formatKeys(key)[0])
}
func (c *Client) SMove(ctx context.Context, source, destination string, member interface{}) *redis.BoolCmd {
	return c.Client.SMove(ctx, c.formatKeys(source)[0], c.formatKeys(destination)[0], member)
}
func (c *Client) SPop(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.SPop(ctx, c.formatKeys(key)[0])
}
func (c *Client) SPopN(ctx context.Context, key string, count int64) *redis.StringSliceCmd {
	return c.Client.SPopN(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) SRandMember(ctx context.Context, key string) *redis.StringCmd {
	return c.Client.SRandMember(ctx, c.formatKeys(key)[0])
}
func (c *Client) SRandMemberN(ctx context.Context, key string, count int64) *redis.StringSliceCmd {
	return c.Client.SRandMemberN(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) SRem(ctx context.Context, key string, members ...interface{}) *redis.IntCmd {
	return c.Client.SRem(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) SUnion(ctx context.Context, keys ...string) *redis.StringSliceCmd {
	return c.Client.SUnion(ctx, c.formatKeys(keys...)...)
}
func (c *Client) SUnionStore(ctx context.Context, destination string, keys ...string) *redis.IntCmd {
	return c.Client.SUnionStore(ctx, c.formatKeys(destination)[0], c.formatKeys(keys...)...)
}

func (c *Client) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *redis.ZWithKeyCmd {
	return c.Client.BZPopMax(ctx, timeout, c.formatKeys(keys...)...)
}
func (c *Client) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *redis.ZWithKeyCmd {
	return c.Client.BZPopMin(ctx, timeout, c.formatKeys(keys...)...)
}

func (c *Client) ZAdd(ctx context.Context, key string, members ...redis.Z) *redis.IntCmd {
	return c.Client.ZAdd(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) ZAddNX(ctx context.Context, key string, members ...redis.Z) *redis.IntCmd {
	return c.Client.ZAddNX(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) ZAddXX(ctx context.Context, key string, members ...redis.Z) *redis.IntCmd {
	return c.Client.ZAddXX(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) ZAddArgs(ctx context.Context, key string, args redis.ZAddArgs) *redis.IntCmd {
	return c.Client.ZAddArgs(ctx, c.formatKeys(key)[0], args)
}
func (c *Client) ZAddArgsIncr(ctx context.Context, key string, args redis.ZAddArgs) *redis.FloatCmd {
	return c.Client.ZAddArgsIncr(ctx, c.formatKeys(key)[0], args)
}
func (c *Client) ZCard(ctx context.Context, key string) *redis.IntCmd {
	return c.Client.ZCard(ctx, c.formatKeys(key)[0])
}
func (c *Client) ZCount(ctx context.Context, key, min, max string) *redis.IntCmd {
	return c.Client.ZCount(ctx, c.formatKeys(key)[0], min, max)
}
func (c *Client) ZLexCount(ctx context.Context, key, min, max string) *redis.IntCmd {
	return c.Client.ZLexCount(ctx, c.formatKeys(key)[0], min, max)
}
func (c *Client) ZIncrBy(ctx context.Context, key string, increment float64, member string) *redis.FloatCmd {
	return c.Client.ZIncrBy(ctx, c.formatKeys(key)[0], increment, member)
}
func (c *Client) ZInter(ctx context.Context, store *redis.ZStore) *redis.StringSliceCmd {
	store.Keys = c.formatKeys(store.Keys...)
	return c.Client.ZInter(ctx, store)
}
func (c *Client) ZInterWithScores(ctx context.Context, store *redis.ZStore) *redis.ZSliceCmd {
	store.Keys = c.formatKeys(store.Keys...)
	return c.Client.ZInterWithScores(ctx, store)
}
func (c *Client) ZInterCard(ctx context.Context, limit int64, keys ...string) *redis.IntCmd {
	return c.Client.ZInterCard(ctx, limit, c.formatKeys(keys...)...)
}
func (c *Client) ZInterStore(ctx context.Context, destination string, store *redis.ZStore) *redis.IntCmd {
	store.Keys = c.formatKeys(store.Keys...)
	return c.Client.ZInterStore(ctx, c.formatKeys(destination)[0], store)
}
func (c *Client) ZMScore(ctx context.Context, key string, members ...string) *redis.FloatSliceCmd {
	return c.Client.ZMScore(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) ZPopMax(ctx context.Context, key string, count ...int64) *redis.ZSliceCmd {
	return c.Client.ZPopMax(ctx, c.formatKeys(key)[0], count...)
}
func (c *Client) ZPopMin(ctx context.Context, key string, count ...int64) *redis.ZSliceCmd {
	return c.Client.ZPopMin(ctx, c.formatKeys(key)[0], count...)
}
func (c *Client) ZRange(ctx context.Context, key string, start, stop int64) *redis.StringSliceCmd {
	return c.Client.ZRange(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *redis.ZSliceCmd {
	return c.Client.ZRangeWithScores(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) ZRangeByScore(ctx context.Context, key string, opt *redis.ZRangeBy) *redis.StringSliceCmd {
	return c.Client.ZRangeByScore(ctx, c.formatKeys(key)[0], opt)
}
func (c *Client) ZRangeByLex(ctx context.Context, key string, opt *redis.ZRangeBy) *redis.StringSliceCmd {
	return c.Client.ZRangeByLex(ctx, c.formatKeys(key)[0], opt)
}
func (c *Client) ZRangeByScoreWithScores(ctx context.Context, key string, opt *redis.ZRangeBy) *redis.ZSliceCmd {
	return c.Client.ZRangeByScoreWithScores(ctx, c.formatKeys(key)[0], opt)
}
func (c *Client) ZRangeArgs(ctx context.Context, z redis.ZRangeArgs) *redis.StringSliceCmd {
	z.Key = c.formatKeys(z.Key)[0]
	return c.Client.ZRangeArgs(ctx, z)
}
func (c *Client) ZRangeArgsWithScores(ctx context.Context, z redis.ZRangeArgs) *redis.ZSliceCmd {
	z.Key = c.formatKeys(z.Key)[0]
	return c.Client.ZRangeArgsWithScores(ctx, z)
}
func (c *Client) ZRangeStore(ctx context.Context, dst string, z redis.ZRangeArgs) *redis.IntCmd {
	z.Key = c.formatKeys(z.Key)[0]
	return c.Client.ZRangeStore(ctx, c.formatKeys(dst)[0], z)
}
func (c *Client) ZRank(ctx context.Context, key, member string) *redis.IntCmd {
	return c.Client.ZRank(ctx, c.formatKeys(key)[0], member)
}
func (c *Client) ZRem(ctx context.Context, key string, members ...interface{}) *redis.IntCmd {
	return c.Client.ZRem(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *redis.IntCmd {
	return c.Client.ZRemRangeByRank(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) ZRemRangeByScore(ctx context.Context, key, min, max string) *redis.IntCmd {
	return c.Client.ZRemRangeByScore(ctx, c.formatKeys(key)[0], min, max)
}
func (c *Client) ZRemRangeByLex(ctx context.Context, key, min, max string) *redis.IntCmd {
	return c.Client.ZRemRangeByLex(ctx, c.formatKeys(key)[0], min, max)
}
func (c *Client) ZRevRange(ctx context.Context, key string, start, stop int64) *redis.StringSliceCmd {
	return c.Client.ZRevRange(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *redis.ZSliceCmd {
	return c.Client.ZRevRangeWithScores(ctx, c.formatKeys(key)[0], start, stop)
}
func (c *Client) ZRevRangeByScore(ctx context.Context, key string, opt *redis.ZRangeBy) *redis.StringSliceCmd {
	return c.Client.ZRevRangeByScore(ctx, c.formatKeys(key)[0], opt)
}
func (c *Client) ZRevRangeByLex(ctx context.Context, key string, opt *redis.ZRangeBy) *redis.StringSliceCmd {
	return c.Client.ZRevRangeByLex(ctx, c.formatKeys(key)[0], opt)
}
func (c *Client) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *redis.ZRangeBy) *redis.ZSliceCmd {
	return c.Client.ZRevRangeByScoreWithScores(ctx, c.formatKeys(key)[0], opt)
}
func (c *Client) ZRevRank(ctx context.Context, key, member string) *redis.IntCmd {
	return c.Client.ZRevRank(ctx, c.formatKeys(key)[0], member)
}
func (c *Client) ZScore(ctx context.Context, key, member string) *redis.FloatCmd {
	return c.Client.ZScore(ctx, c.formatKeys(key)[0], member)
}
func (c *Client) ZUnionStore(ctx context.Context, dest string, store *redis.ZStore) *redis.IntCmd {
	store.Keys = c.formatKeys(store.Keys...)
	return c.Client.ZUnionStore(ctx, c.formatKeys(dest)[0], store)
}
func (c *Client) ZRandMember(ctx context.Context, key string, count int) *redis.StringSliceCmd {
	return c.Client.ZRandMember(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) ZRandMemberWithScores(ctx context.Context, key string, count int) *redis.ZSliceCmd {
	return c.Client.ZRandMemberWithScores(ctx, c.formatKeys(key)[0], count)
}
func (c *Client) ZUnion(ctx context.Context, store redis.ZStore) *redis.StringSliceCmd {
	store.Keys = c.formatKeys(store.Keys...)
	return c.Client.ZUnion(ctx, store)
}
func (c *Client) ZUnionWithScores(ctx context.Context, store redis.ZStore) *redis.ZSliceCmd {
	store.Keys = c.formatKeys(store.Keys...)
	return c.Client.ZUnionWithScores(ctx, store)
}
func (c *Client) ZDiff(ctx context.Context, keys ...string) *redis.StringSliceCmd {
	return c.Client.ZDiff(ctx, c.formatKeys(keys...)...)
}
func (c *Client) ZDiffWithScores(ctx context.Context, keys ...string) *redis.ZSliceCmd {
	return c.Client.ZDiffWithScores(ctx, c.formatKeys(keys...)...)
}
func (c *Client) ZDiffStore(ctx context.Context, destination string, keys ...string) *redis.IntCmd {
	return c.Client.ZDiffStore(ctx, c.formatKeys(destination)[0], c.formatKeys(keys...)...)
}

func (c *Client) PFAdd(ctx context.Context, key string, els ...interface{}) *redis.IntCmd {
	return c.Client.PFAdd(ctx, c.formatKeys(key)[0], els...)
}
func (c *Client) PFCount(ctx context.Context, keys ...string) *redis.IntCmd {
	return c.Client.PFCount(ctx, c.formatKeys(keys...)...)
}
func (c *Client) PFMerge(ctx context.Context, dest string, keys ...string) *redis.StatusCmd {
	return c.Client.PFMerge(ctx, c.formatKeys(dest)[0], c.formatKeys(keys...)...)
}

func (c *Client) GeoAdd(ctx context.Context, key string, geoLocation ...*redis.GeoLocation) *redis.IntCmd {
	return c.Client.GeoAdd(ctx, c.formatKeys(key)[0], geoLocation...)
}
func (c *Client) GeoPos(ctx context.Context, key string, members ...string) *redis.GeoPosCmd {
	return c.Client.GeoPos(ctx, c.formatKeys(key)[0], members...)
}
func (c *Client) GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *redis.GeoRadiusQuery) *redis.GeoLocationCmd {
	return c.Client.GeoRadius(ctx, c.formatKeys(key)[0], longitude, latitude, query)
}
func (c *Client) GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *redis.GeoRadiusQuery) *redis.IntCmd {
	return c.Client.GeoRadiusStore(ctx, c.formatKeys(key)[0], longitude, latitude, query)
}
func (c *Client) GeoRadiusByMember(ctx context.Context, key, member string, query *redis.GeoRadiusQuery) *redis.GeoLocationCmd {
	return c.Client.GeoRadiusByMember(ctx, c.formatKeys(key)[0], member, query)
}
func (c *Client) GeoRadiusByMemberStore(ctx context.Context, key, member string, query *redis.GeoRadiusQuery) *redis.IntCmd {
	return c.Client.GeoRadiusByMemberStore(ctx, c.formatKeys(key)[0], member, query)
}
func (c *Client) GeoSearch(ctx context.Context, key string, q *redis.GeoSearchQuery) *redis.StringSliceCmd {
	return c.Client.GeoSearch(ctx, c.formatKeys(key)[0], q)
}
func (c *Client) GeoSearchLocation(ctx context.Context, key string, q *redis.GeoSearchLocationQuery) *redis.GeoSearchLocationCmd {
	return c.Client.GeoSearchLocation(ctx, c.formatKeys(key)[0], q)
}
func (c *Client) GeoSearchStore(ctx context.Context, key, store string, q *redis.GeoSearchStoreQuery) *redis.IntCmd {
	return c.Client.GeoSearchStore(ctx, c.formatKeys(key)[0], store, q)
}
func (c *Client) GeoDist(ctx context.Context, key string, member1, member2, unit string) *redis.FloatCmd {
	return c.Client.GeoDist(ctx, c.formatKeys(key)[0], member1, member2, unit)
}
func (c *Client) GeoHash(ctx context.Context, key string, members ...string) *redis.StringSliceCmd {
	return c.Client.GeoHash(ctx, c.formatKeys(key)[0], members...)
}
